package monsmon.game.parse;

import monsmon.game.*;
import monsmon.game.tmlt.*;
import java.util.*;
import java.lang.reflect.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import java.io.*;
import java.util.regex.*;
import javax.xml.namespace.QName;
import monsmon.util.*;
import java.awt.Color;

import static monsmon.game.parse.XMLParser.*;

public class Parser{


	private static void __merge_lvls(HashMap<String, LevelStrs> m1,
			HashMap<String, LevelStrs> m2){
		for(String m2s : m2.keySet()){
			LevelStrs l2 = m2.get(m2s);
			if(m1.get(m2s) != null){
				LevelStrs l1 = m1.get(m2s);
				l1.ctrl += l2.ctrl;
				l1.def += l2.def;
				l1.map += l2.map;
				l1.script += l2.script;
			}else{
				m1.put(m2s, l2);
			}
		}
	}


	public static MonsGame parse(String files[]){
		StringBuilder mondef = new StringBuilder("<monsmon>");
		StringBuilder globals = new StringBuilder();
		HashMap<String, LevelStrs> lvls = new HashMap
			<String, LevelStrs>();
		for(String f: files){
			FileDat fd = PreProccesser.preproc(f);
			mondef.append(fd.monsdef);
			globals.append(fd.glbl);
			__merge_lvls(lvls, fd.lvls);
		}
		mondef.append("</monsmon>");
		MonsGame gm = new MonsGame();
		gm.gd = __pglobals(mondef.toString());
		__mk_lvls(lvls, gm);
		__p_global(gm, globals.toString());
		return gm;
	}

	private static void __mk_lvls(HashMap<String, LevelStrs> lvls, 
			MonsGame gm){
		for(Map.Entry<String, LevelStrs> ent : lvls.entrySet()){
			LevelStrs lvl = ent.getValue();
			lvl.tiles = new HashMap(gm.gd.tiles);
			lvl.aliases = new HashMap(gm.gd.talias);
			__p_ldef(ent.getValue());
			ent.getValue().name = ent.getKey();
			LvlC.parse(ent.getValue(), gm);
		}
	}
	//Parses the def section of the level
	//Data put in LevelStrs hashmaps
	private static void __p_ldef(LevelStrs l){
		XMLEventReader rdr = __get_reader_xml(l.def + "</def>");
		HashMap<String, TileT> tiles = new HashMap<String, TileT>();
		while(rdr.hasNext()){
			XMLEvent e = __get_event(rdr);
			if(e == null) break;
			if(e.isEndElement()){
				if(__get_str(e).equals("dat")) break;
			}
			if(e.isStartElement()){
				if(__get_str(e).equals("tile")){
					TileT t = __p_tile(rdr, 
						e.asStartElement());
					l.tiles.put(t.name, t);
				}
			}
		}
	}

	///////////////////////////////////////////////////////////////////
	//	Game data proccesser.
	//Reads the global xml defines
	//returns a GlobalDat containing the info
	private static GlobalDat __pglobals(String monsdef){
		XMLEventReader rdr = __get_reader_xml(monsdef);
		GlobalDat gbl = new GlobalDat();
		while(rdr.hasNext()){
			XMLEvent e = __get_event(rdr);
			if(e == null) break;
//			System.out.println("Event: "+e);
			if(e.isStartElement()){
				StartElement se = e.asStartElement();
				String name = __get_str(e);
				if("monsmon".equals(name)){
					continue;
				}else if("move".equals(name)){
					MoveT mv = __read_move(rdr, se);
					if(mv != null){
						gbl.moves.put(mv.name, mv);
					}
				}else if("mons".equals(name)){
					MonsT m = __read_mons(rdr, se);
					if(m != null){
						gbl.monst.put(m.fname, m);
					}
				}else if("tile".equals(name)){
					TileT t = __p_tile(rdr, se);
					if(t != null){
						gbl.add_tile(t);
					}
				}else if("entity".equals(name)){
					EntT en = __p_ent(rdr, se);
					if(en != null){
						gbl.add_ent(en);
					}
				}else{
					System.err.print("Unknown start element"
						+ " " + name);
				}
			}else if(e.isEndElement()){
				if(__get_str(e).equals("monsmon")){
					break;
				}
			}

		}	
		return gbl;
	}
	/////////////////////////////////////////////////////////////////////
	//	Global CTRL parser
	//		
	private static void __p_global(MonsGame gm, String gbls){
		String[] cmds = gbls.split("\n");
		for(String cmd: cmds){
			Matcher m = LvlC.comment.matcher(cmd);
			cmd = m.replaceAll("");
			m = LvlC.call.matcher(cmd);
			if(m.matches()){
				Method mt = null;
				if(m.group(1).charAt(0) == '_'){
					System.err.print("Attempted to call "
						+"restricted function: "+
						m.group(1));
					continue;
				}
				try{
					mt = Parser.class.getDeclaredMethod(
						'_' + m.group(1),
						Args.class, MonsGame.class);
				}catch(Exception ex){
					mt = null;
				}
				if(mt != null){
					try{
						mt.invoke(null, 
							new Args(m.group(2)),
							gm);
					}catch(Exception ex){
						ex.printStackTrace();
					}
				}else{
					System.err.println("Bad GCRTL call: " +
						cmd);
				}
				continue;
			}
			
			//if nothing matches
			cmd = cmd.trim();
			if(!"".equals(cmd)){
				System.err.print("Unknown GCRTL command: " +
					cmd);
			}
		}
	}	
	
	//////////////////////////////////////////////////////////////////
	//			GCRTL functions
	//////////////////////////////////////////////////////////////////
	//	
	//
	
	static void _put_player(Args args, MonsGame gm){
		String lvln = args.a1;
		int x = Integer.parseInt(args.a2);
		int y = Integer.parseInt(args.a3);
		String ptemp = args.a4;
		EntT et = gm.gd.gent.get(ptemp);
		gm.set_current_lvl(lvln);	
		Entity pl = new Entity(x, y, gm.get_current_lvl(), et);
		gm.player = pl;
	}


}
